Skip to content

feat: Add optional support for per-context summary events.#135

Merged
kinyoklion merged 5 commits intomainfrom
rlamb/support-per-context-summary-events
Feb 12, 2026
Merged

feat: Add optional support for per-context summary events.#135
kinyoklion merged 5 commits intomainfrom
rlamb/support-per-context-summary-events

Conversation

@kinyoklion
Copy link
Member

@kinyoklion kinyoklion commented Feb 10, 2026

Note

Medium Risk
Touches core analytics event buffering/flush and JSON output paths; enabling per-context summarization changes payload shape/volume and includes context data in summary events, so regressions could affect event delivery and privacy expectations.

Overview
Adds an optional per-context summarization mode that can emit multiple summary events per flush (one per LDContext) instead of a single aggregated summary.

Refactors the event pipeline to use a new EventSummarizerInterface with AggregatedEventSummarizer (backward-compatible default) and PerContextEventSummarizer, extends EventsConfiguration with a perContextSummarization flag, and updates DefaultEventProcessor/EventOutputFormatter to send/restore a list of summaries and to include serialized context in summary output when present. Tests are updated and a comprehensive PerContextEventSummarizerTest is added.

Written by Cursor Bugbot for commit 3a0f579. This will update automatically on new commits. Configure here.

@kinyoklion
Copy link
Member Author

bugbot review

@kinyoklion kinyoklion marked this pull request as ready for review February 10, 2026 22:43
@kinyoklion kinyoklion requested a review from a team as a code owner February 10, 2026 22:43
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

EventSummarizer summarizer = summarizersByContext.get(context);
if (summarizer == null) {
summarizer = new EventSummarizer(context);
summarizersByContext.put(context, summarizer);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using LDContext as HashMap key causes incorrect grouping

Medium Severity

PerContextEventSummarizer uses LDContext as a HashMap key, but LDContext.equals()/hashCode() compare all attributes (name, anonymous, custom attributes, private attributes), not just identity (kind + key). Two contexts representing the same user but with different attribute values would produce separate summaries instead of being grouped together. Additionally, LDContext.hashCode() is explicitly documented as inefficient and "not an anticipated or recommended use case" for map keys. The existing ServerSideEventContextDeduplicator demonstrates the correct pattern: keying by getFullyQualifiedKey().

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is describing the correct behavior. We want summaries grouped by their exact context accounting for all attributes.

The performance isn't a concern for this use-case. (Even then the performance of this is actually fine given the number of attributes contexts have in practice.)

*/
@Override
public void restoreTo(List<EventSummarizer.EventSummary> previousSummaries) {
summarizersByContext.clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there data in these summarizers that needs to be merged with previousSummaries?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the original implementation just re-assigned the event state to the previous state.

Really this clear is somewhat redundant. The way these thread handling works there shouldn't be any events added to the summarizer, because this work, and processing events, are single threaded. So the run loop could be working on this, or it could be processing an event, or so forth.

@Override
public void restoreTo(List<EventSummarizer.EventSummary> previousSummaries) {
summarizersByContext.clear();
for (EventSummarizer.EventSummary summary : previousSummaries) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How large may this previousSummaries list be in practice? Seems possible to be hundreds/thousands?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its a client-side feature, and this would be tied to the flush interval, so it should be small.

Worth noting I have never seen this feature in any other SDK. Other SDKs just drop the summaries.

Per-context summary events are, in general, not something we could do in a high cardinality context environment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be large if you have like a rampant identify loop. And unreliable/unavailable networking.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, being as this is called based on the flush worker not being available, I think it wouldn't really grow. Unless somehow the flush worker setup is broken in another way. Like all of them can become stalled for unbounded time.

@kinyoklion kinyoklion merged commit 3913d6f into main Feb 12, 2026
19 checks passed
@kinyoklion kinyoklion deleted the rlamb/support-per-context-summary-events branch February 12, 2026 21:55
kinyoklion pushed a commit that referenced this pull request Feb 12, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.8.0](launchdarkly-java-sdk-internal-1.7.0...launchdarkly-java-sdk-internal-1.8.0)
(2026-02-12)


### Features

* Add optional support for per-context summary events.
([#135](#135))
([3913d6f](3913d6f))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Release/versioning metadata and changelog updates only; no functional
code changes in this diff.
> 
> **Overview**
> Prepares the `lib/shared/internal` package release `1.8.0` by updating
version metadata in `.release-please-manifest.json` and
`lib/shared/internal/gradle.properties`.
> 
> Updates `lib/shared/internal/CHANGELOG.md` with the `1.8.0` entry
noting *optional support for per-context summary events*.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
55358e5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants